#!/usr/bin/env python3
"""
设备指纹管理器 - 第一阶段增强
负责生成和管理真实的设备指纹，对抗指纹识别
"""

import logging
import random
import json
import time
from typing import Dict, List, Optional, Any
from pathlib import Path

logger = logging.getLogger(__name__)

class FingerprintManager:
    """设备指纹管理器 - 增强版"""
    
    def __init__(self):
        self.fingerprint_profiles = self.load_fingerprint_profiles()
        self.current_fingerprint = None
        self.last_rotation_time = 0
        self.rotation_interval = 1800  # 30分钟轮换一次
        
    def load_fingerprint_profiles(self) -> List[Dict[str, Any]]:
        """加载真实设备指纹配置文件"""
        profiles_file = Path(__file__).parent.parent / "config" / "fingerprint_profiles.json"
        
        try:
            if profiles_file.exists():
                with open(profiles_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
        except Exception as e:
            logger.warning(f"[FINGERPRINT] 加载配置失败: {e}")
        
        # 默认指纹配置
        return [
            {
                "profile_id": "chrome_win10_1920",
                "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
                "viewport": {"width": 1920, "height": 1080},
                "screen": {"width": 1920, "height": 1080, "colorDepth": 24},
                "timezone": "Asia/Shanghai",
                "language": "zh-CN",
                "platform": "Win32",
                "hardware_concurrency": 8,
                "device_memory": 8,
                "webgl_vendor": "Google Inc. (Intel)",
                "webgl_renderer": "ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)",
                "fonts": ["Arial", "Times New Roman", "Courier New", "Verdana", "Georgia", "Palatino", "Garamond", "Bookman", "Comic Sans MS", "Trebuchet MS", "Arial Black", "Impact"]
            },
            {
                "profile_id": "chrome_win10_1366",
                "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
                "viewport": {"width": 1366, "height": 768},
                "screen": {"width": 1366, "height": 768, "colorDepth": 24},
                "timezone": "Asia/Shanghai",
                "language": "zh-CN",
                "platform": "Win32",
                "hardware_concurrency": 4,
                "device_memory": 4,
                "webgl_vendor": "Google Inc. (NVIDIA)",
                "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 1050 Ti Direct3D11 vs_5_0 ps_5_0, D3D11)",
                "fonts": ["Arial", "Times New Roman", "Courier New", "Verdana", "Georgia", "Palatino", "Garamond", "Bookman", "Comic Sans MS", "Trebuchet MS", "Arial Black", "Impact"]
            }
        ]
    
    def should_rotate_fingerprint(self) -> bool:
        """判断是否需要轮换指纹"""
        return time.time() - self.last_rotation_time > self.rotation_interval
    
    def get_current_fingerprint(self) -> Dict[str, Any]:
        """获取当前指纹，必要时进行轮换"""
        if self.current_fingerprint is None or self.should_rotate_fingerprint():
            self.current_fingerprint = random.choice(self.fingerprint_profiles)
            self.last_rotation_time = time.time()
            logger.info(f"[FINGERPRINT] 轮换到新指纹: {self.current_fingerprint['profile_id']}")
        
        return self.current_fingerprint
    
    def generate_canvas_noise_script(self) -> str:
        """生成Canvas指纹噪声注入脚本"""
        noise_factor = random.uniform(0.0001, 0.001)
        
        return f"""
        // Canvas指纹噪声注入
        const getContext = HTMLCanvasElement.prototype.getContext;
        HTMLCanvasElement.prototype.getContext = function(type) {{
            const context = getContext.call(this, type);
            if (type === '2d') {{
                const originalFillText = context.fillText;
                context.fillText = function(text, x, y, maxWidth) {{
                    const noise = (Math.random() - 0.5) * {noise_factor};
                    return originalFillText.call(this, text, x + noise, y + noise, maxWidth);
                }};
                
                const originalStrokeText = context.strokeText;
                context.strokeText = function(text, x, y, maxWidth) {{
                    const noise = (Math.random() - 0.5) * {noise_factor};
                    return originalStrokeText.call(this, text, x + noise, y + noise, maxWidth);
                }};
            }}
            return context;
        }};
        """
    
    def generate_webgl_noise_script(self) -> str:
        """生成WebGL指纹噪声注入脚本"""
        return """
        // WebGL指纹噪声注入
        const getParameter = WebGLRenderingContext.prototype.getParameter;
        WebGLRenderingContext.prototype.getParameter = function(parameter) {
            if (parameter === 37445) { // UNMASKED_VENDOR_WEBGL
                return 'Google Inc. (Intel)';
            }
            if (parameter === 37446) { // UNMASKED_RENDERER_WEBGL
                return 'ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)';
            }
            return getParameter.call(this, parameter);
        };
        """
    
    def generate_audio_noise_script(self) -> str:
        """生成音频指纹噪声注入脚本"""
        return """
        // 音频指纹噪声注入
        const audioContext = window.AudioContext || window.webkitAudioContext;
        if (audioContext) {
            const originalCreateAnalyser = audioContext.prototype.createAnalyser;
            audioContext.prototype.createAnalyser = function() {
                const analyser = originalCreateAnalyser.call(this);
                const originalGetFloatFrequencyData = analyser.getFloatFrequencyData;
                analyser.getFloatFrequencyData = function(array) {
                    originalGetFloatFrequencyData.call(this, array);
                    // 添加微小噪声
                    for (let i = 0; i < array.length; i++) {
                        array[i] += (Math.random() - 0.5) * 0.0001;
                    }
                };
                return analyser;
            };
        }
        """
    
    def get_stealth_script(self) -> str:
        """获取完整的反检测脚本"""
        fingerprint = self.get_current_fingerprint()
        
        return f"""
        // 移除webdriver标识
        Object.defineProperty(navigator, 'webdriver', {{
            get: () => undefined
        }});
        
        // 伪装硬件信息
        Object.defineProperty(navigator, 'hardwareConcurrency', {{
            get: () => {fingerprint['hardware_concurrency']}
        }});
        
        Object.defineProperty(navigator, 'deviceMemory', {{
            get: () => {fingerprint['device_memory']}
        }});
        
        // 伪装语言设置
        Object.defineProperty(navigator, 'language', {{
            get: () => '{fingerprint['language']}'
        }});
        
        Object.defineProperty(navigator, 'languages', {{
            get: () => ['{fingerprint['language']}']
        }});
        
        // 伪装平台信息
        Object.defineProperty(navigator, 'platform', {{
            get: () => '{fingerprint['platform']}'
        }});
        
        // 伪装屏幕信息
        Object.defineProperty(screen, 'width', {{
            get: () => {fingerprint['screen']['width']}
        }});
        
        Object.defineProperty(screen, 'height', {{
            get: () => {fingerprint['screen']['height']}
        }});
        
        Object.defineProperty(screen, 'colorDepth', {{
            get: () => {fingerprint['screen']['colorDepth']}
        }});
        
        // 伪装时区
        Date.prototype.getTimezoneOffset = function() {{
            return -480; // 北京时间
        }};
        
        // 伪装插件信息
        Object.defineProperty(navigator, 'plugins', {{
            get: () => [
                {{
                    name: 'Chrome PDF Plugin',
                    filename: 'internal-pdf-viewer',
                    description: 'Portable Document Format'
                }},
                {{
                    name: 'Chrome PDF Viewer',
                    filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
                    description: ''
                }}
            ]
        }});
        
        {self.generate_canvas_noise_script()}
        {self.generate_webgl_noise_script()}
        {self.generate_audio_noise_script()}
        
        console.log('[STEALTH] 反检测脚本已加载');
        """
    
    def get_browser_args(self) -> List[str]:
        """获取浏览器启动参数"""
        return [
            '--no-sandbox',
            '--disable-blink-features=AutomationControlled',
            '--disable-web-security',
            '--disable-features=VizDisplayCompositor',
            '--disable-dev-shm-usage',
            '--disable-extensions',
            '--disable-plugins',
            '--disable-images',  # 禁用图片加载，提高速度
            '--disable-javascript-harmony-shipping',
            '--disable-background-timer-throttling',
            '--disable-backgrounding-occluded-windows',
            '--disable-renderer-backgrounding',
            '--disable-field-trial-config',
            '--disable-ipc-flooding-protection',
            '--exclude-switches=enable-automation',
            '--disable-client-side-phishing-detection',
            '--disable-sync',
            '--disable-background-networking',
            '--disable-default-apps'
        ]
